﻿#include <iostream>

enum imageType
{
	LSAT, SPOT
};


//------------------------ Image --------------------

class Image
{
public:
	//Image() {}
	//~Image() {}

	virtual void draw() = 0;
	static Image *findAndClone(imageType type);
protected:
	virtual imageType returnType() = 0;
	virtual Image *clone() = 0;

	// 声明Image的每个子类时，它会注册其原型
	static void addPrototype(Image *image)
	{
		_prototypes[_nextSlot++] = image;
		std::cout << _nextSlot << std::endl;
	}
private:
	//addPrototype() 会保存每个注册过原型到这里
	static Image* _prototypes[10];
	static int _nextSlot;
};

Image *Image::_prototypes[];
int Image::_nextSlot;

//当你需要初始化一个image 子类的实例时，通过用户调用这个公开的静态成员函数。
Image* Image::findAndClone(imageType type)
{
	for (int i = 0; i < _nextSlot; i++)
	{
		if (_prototypes[i]->returnType() == type)
		{
			return _prototypes[i]->clone();
		}
	}
	return NULL;
}



//------------------------ LandSatImage --------------------

class LandSatImage : public Image
{
public:
	imageType returnType()
	{
		return LSAT;
	}

	void draw()
	{
		std::cout << "LandSatImage::draw" << "\t" << _id  << "\t" << __LINE__ << std::endl;
	}

	//当一个 clone 函数被调用是，内部会调用一个伪参数的单参构造函数
	Image *clone() override
	{
		return new LandSatImage(1);
	}
protected:
	//这个ctor 只能被clone() 调用
	LandSatImage(int dummy)
	{
		_id = _count++;
	}
private:
	//初始化一个Image 子类机制——默认的构造函数的调用。
	// 它会注册子类的原型
	static LandSatImage _landSatImage;
	//仅在初始化私有静态数据成员时调用此方法
	LandSatImage()
	{
		addPrototype(this);
	}
	//每个实例机制的名义“state”
	int _id;
	static int _count;
};

//注册子类的原型
LandSatImage LandSatImage::_landSatImage;
//初始化实例机制的名义“state”,
int LandSatImage::_count = 1;

//------------------------ SpotImage --------------------s
class SpotImage : public Image
{
public:
	imageType returnType()
	{
		return SPOT;
	}

	void draw()
	{
		std::cout << "SpotImage::draw" << "\t" << _id << "\t" << __LINE__ << std::endl;
	}

	//当一个 clone 函数被调用是，内部会调用一个伪参数的单参构造函数
	Image *clone() override
	{
		return new SpotImage(1);
	}
protected:
	//这个ctor 只能被clone() 调用
	SpotImage(int dummy)
	{
		_id = _count++;
	}
private:
	// 它会注册子类的原型
	static SpotImage _SpotImage;
	SpotImage()
	{
		addPrototype(this);
	}
	int _id;
	static int _count;
};

SpotImage SpotImage::_SpotImage;
int SpotImage::_count = 1;

const int NUM_IMAGES = 8;

imageType input[NUM_IMAGES] = {
	LSAT, LSAT, LSAT, SPOT, LSAT, SPOT, SPOT, LSAT
};

int main(void)
{
	Image *images[NUM_IMAGES];
	//给出一个image 类型，找到合适的原型，并返回一个clone
	for (int i = 0; i < NUM_IMAGES; i++)
	{
		images[i] = Image::findAndClone(input[i]);
	}

	for (int i = 0; i < NUM_IMAGES; i++)
	{
		if (images[i] != NULL)
		{
			images[i]->draw();
		}
	}

	for (int i = 0; i < NUM_IMAGES; i++)
	{
		if (images[i] != NULL)
		{
			delete images[i];
		}
	}
}

